Skip to content

refactor(cli): extract turn run-once execution owner - #5380

Merged
huangruiteng merged 22 commits into
mainfrom
codex/fix-turn-run-once-owner
Oct 2, 2026
Merged

huangruiteng merged 22 commits into
mainfrom
codex/fix-turn-run-once-owner

Conversation

@Duang777

Copy link
Copy Markdown
Collaborator

Goal And Delivered Outcome

  • Outcome basis / optional anchor: restore the command-module ownership budget on current main without changing Turn behavior.
  • Goal/source and gap: loopx/cli_commands/turn.py had grown to 1,128 lines and exceeded its historical 1,114-line exception.
  • Observable before → after, with the validation row that proves it: the command owner is now 298 lines and the extracted run-once owner is 890 lines; both pass the default 1,000-line budget.
  • Issue/task and intended base: maintenance fix against main at f49b4a00870604d39fa4318da24d6dd35e72bb6e.

Scope And Continuation

  • Completed scope and remaining work: moved the complete run-once execution and settlement adapter into turn_run_once.py, retained lazy loading for non-executing commands, and updated test injection targets. Complete within this scope.
  • Slice boundary / successor: N/A; no behavioral or public API change is intended.

Validation

  • Tested revision: fcea927f6c9664f79f3623b7a62e587eca4b67f2
  • Run state: finished
  • Input classes: synthetic, public_fixture
Check kind Result Public-safe evidence / limitation
unit passed Six affected suites: 185 passed, 2 skipped.
static passed Ruff passed on changed Python paths; mypy reported no issues in 19 source files.
real_entrypoint passed python examples/loopx-turn-dsh-e2e-smoke.py completed a committed Turn, spent one quota slot, and replayed with all effect flags false.
regression_parity passed The 42-statement execution block and extracted helper are AST-equivalent after the intentional local-name and return normalization.
static passed Module-size ownership, docs-governance, repository-hygiene, semantic-vocabulary, cold help/import, and selected premerge checks passed.
manual passed Two grouped reviews plus a cross-group contract review found no P0-P2 defects.
  • Coverage and gaps: the tests cover planning-only lazy import, built-in Codex and DSH hosts, validation, durable completion, quota settlement, replay recovery, capability hooks, and journal inspection. No untested changed path was identified.

See validation disclosure guidance.

Frontend / Visual Evidence

  • UI impact: none
  • Before: N/A
  • After: N/A
  • States and viewports shown: N/A
  • Source data: none
  • Attention review: N/A; CLI module ownership only.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Refactoring (no functional changes)
  • Documentation update
  • Test update

LoopX Area

  • Control plane (goals, todos, quota, scheduler, registry, runtime)
  • Benchmark boundary (adapters, runners, verifiers, scoring, evidence)
  • Capability or extension (providers, adapters, skills)
  • Public docs or presentation surface (README, protocols, dashboard)
  • Build, packaging, installer, or CI
  • Host or runtime integration

Technical Direction

  • Direction / acceptance reference, when applicable: Core control-plane hardening.

Shared-authority RFC fixture impact

N/A. This refactor does not claim progress against the TypeScript control-plane migration or shared Goal Authority RFC.

Boundary Checklist

  • Neither the diff nor this PR body/comments/attachments disclose private state, credentials, raw traces or verifier output, internal links, or local machine paths (including .loopx/, .codex/goals/, and live ACTIVE_GOAL_STATE.md).
  • I did not duplicate maintainer-owned benchmark work unless a maintainer split out a public issue for it.
  • I kept the change scoped to the linked issue/task.
  • I completed the visual evidence section for UI changes, or marked UI impact none.
  • Every commit includes a DCO Signed-off-by trailer (git commit -s).

Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>
@Duang777

Copy link
Copy Markdown
Collaborator Author

Exact-head CI attribution for fcea927f6c9664f79f3623b7a62e587eca4b67f2:

None of the three failing owners is modified by this PR, and no failure points into the extracted turn_run_once.py boundary or its adjusted tests. The branch remains unchanged. @cocolord @huangruiteng please review this exact head when available. No merge action was taken.

…ce-owner

Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>
@Duang777

Duang777 commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator Author

Exact-head update for 8812eb2952c91756bb7355507f851a9f8a798674:

Fresh CI is running on this exact head. @cocolord @huangruiteng please review when available. No merge action was taken.

…ce-owner

Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>

# Conflicts:
#	loopx/cli_commands/turn.py
#	tests/test_codex_operation_host.py
…ce-owner

Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>
@Duang777

Duang777 commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator Author

Exact-head update for c2fb27349d8ef592de2b5787b0adca069c23886e on main@3ad3269af4d2cfae2085693823dcfcda522f9a2b:

  • Resolved the fix(operations): allow admitted prepare with a registered source audience #5378 merge conflict by keeping the extracted turn_run_once.py owner, retaining the CLI source-route guard in turn.py, forwarding source_route from the extracted host adapter, and moving the test monkeypatch to the new owner. No old run-once implementation was restored.
  • The resolved integration passed 195 Python tests with 2 skips and Ruff.
  • After test(host): publish process markers atomically #5365 entered main, the affected Host/Codex CLI suite passed again: 65 passed, 2 skipped.
  • git diff --check passed; the local untracked uv.lock remained byte-for-byte unchanged and was not staged.

Both merge commits carry Signed-off-by; no history was rewritten remotely. Fresh CI is running. @cocolord @huangruiteng please review when available. No merge action was taken.

…ce-owner

Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>
…ce-owner

Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>
@Duang777

Duang777 commented Oct 1, 2026 •

Copy link
Copy Markdown
Collaborator Author

Exact-head update for 5e6f44d7f03100afb904cde53c31b6b0f8ec677b on main@3c50e59c0c3da96ac00b1715e7978440030c13a9:

Fresh exact-head CI is running. No merge action was taken.

@mergify

mergify Bot commented Oct 1, 2026

Copy link
Copy Markdown

This pull request has merge conflicts with main and cannot be merged
until they are resolved. Please rebase or merge the base branch, @Duang777.

Choose the remote for the base repository, not an out-of-date fork.
For a fork clone, first inspect git remote -v; upstream must point
to https://github.com/loopx-project/loopx.git. If it is absent, add it
with git remote add upstream https://github.com/loopx-project/loopx.git.
Then run:

git fetch upstream
git rebase upstream/main
# Resolve each conflict, git add the resolved files, then git rebase --continue.
git push --force-with-lease origin HEAD

For a same-repository clone whose origin points to
https://github.com/loopx-project/loopx.git, use origin instead of
upstream for fetch/rebase. If you prefer merging the base, use
git merge <base-remote>/main and push normally.

Keep the DCO Signed-off-by trailer on every commit when you rebase.
https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork

@mergify mergify Bot added the needs-rebase Mergify: the pull request has merge conflicts with its base branch label Oct 1, 2026
…ce-owner

Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>

# Conflicts:
#	loopx/cli_commands/turn.py
@mergify mergify Bot removed the needs-rebase Mergify: the pull request has merge conflicts with its base branch label Oct 1, 2026
…ce-owner

Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>
…ce-owner

Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>
…ce-owner

Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>
…ce-owner

Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>
…ce-owner

Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>
…ce-owner

Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>
…ce-owner

Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>
…ce-owner

Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>
…ce-owner

Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>
…ce-owner

Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>
…ce-owner

Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>
Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>
Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>
Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>

@huangruiteng huangruiteng left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

动机

未发现阻塞问题。评审 exact head:43507c2814a90ad5b039c9edf333deea9e0f9d7f,immutable base:3dbde34e15122b31d447a8a640139dd676e41d11。目标是把真正超预算的 Turn 命令 owner 分成可定位、可回滚的规划和执行 IO 边界,同时保持用户原来的命令、验证、结算和恢复行为。实测 base 的 turn.py 是 1135 行,超过冻结的 1114 行;新 head 的 command 为 311 行,完整执行 adapter 为 898 行,二者都受原有 1000 行默认上限约束,没有上调预算。

改动思路

采用现有 owner 的最小完整抽取,而不是新增 executor、Capability、状态机或第二套 TypeScript/Python 决策。命令保留参数/GoalRef/preflight、plan/inspect/capability-action 分支;只有普通 run-once 路径才 lazy import 执行 adapter。Python 保留 host 和 provider IO 适配合理,语义 owner、持久 journal、effect identity 和 typed settlement 规则继续复用既有实现。这是可独立验收的维护切片,不宣称完成 TypeScript migration 或整个 Goal authority roadmap。

正向旅程仍为命令 -> scoped plan -> host -> 独立 validator -> durable writeback/Todo continuation -> 单次 quota spend -> journal/readback -> 原 Turn 重放。用户没有新的开关、重复输入或确认步骤;不执行的计划和 capability action 不进入普通 host transaction。

具体改动

关键代码讲解

  • handle_turn_command(loopx/cli_commands/turn.py:52):保留 source-route 的显式 opt-in、原始 resumed Turn/Agent 身份检查,以及 planning/capability 的早返回;284–286 行 lazy 调用抽取后的 adapter,不执行的命令不加载它。
  • execute_turn_run_once(turn_run_once.py:66):显式接收当前 prepared plan、registry/runtime、Goal admission、operator context;完整绑定原来的 generic/Codex/DSH host、独立 validation、completion/writeback/spend、scheduler 和 reflection 回调。没有增加新请求版本或永久并行入口。
  • writeback_resolver(同文件 570 行)及相邻 spend/terminal resolver:仍读原 identity 的持久事实,区分 absent、unknown 和 committed;缺失 receipt 可修复,未知读回不能被假装成未执行。函数尾异常路径仍保留 journal_observation 和 effects 的未知值,而不是把执行后的异常渲染为全 false。

全部九个 changed paths 已读:两处生产 owner 抽取、六个测试文件更新实际 fault-injection/import target,并加强 plan、inspect-journal、calendar capability 不执行的断言;module-size smoke 删除旧 turn.py 特例,没有减少扫描范围。+978/-883 主要是移动,不是增加 898 行新决策规则。当前 main 83faf456f 相对于本 base 未修改这两个 CLI 文件;相关 #5417 另行承担 typed provider admission/recovery,不把本 PR 的 Python IO 移动误称为它的语义迁移。

独立检查旧执行块的 42 个 AST statements 和异常 handler 均等价,仅允许 strict_goal_admission 参数重命名、最终 assignment 转 return、已知 run-once 命令常量化三项归一化。相同六文件原生矩阵在 base/head 都是 212 passed、2 skipped。两项 skip 是原有显式 live-host release opt-in 下的模型参数 case;未启用、未进行付费模型调用,不能把 skipped 写成已验证。

对主干的风险

最大风险是抽取时丢掉 validator、source route、effect ref,或者错误地把 durable completion/扣费后的崩溃当成未发生。原生矩阵保留真实 File completion/spend checkpoint interruption、successor/terminal、receipt 恢复、Codex owned transport 和 CLI 冷加载负例,没有改成直接 mock 一个成功结果。

另在两个 immutable checkout 通过实际 CLI 和临时 File backend 运行 examples/loopx-turn-dsh-e2e-smoke.py:独立 marker 校验成立、持久 quota 仅一次,原 key replay 的四个 effect flags 全 false。只有 DSH harness 是合成 runner,生产 CLI/adapter/validator/writeback/journal 都实际执行;不声称验证真实模型、Windows 或 PostgreSQL。五组相同 CLI 输入分别覆盖 preview、非法 host JSON、缺失 host argv、非法 validator JSON,以及 Operation 关闭时传 source route,完整 error/schema/mode/validation/effect 输出一致,不只是两个 reason codes 相同。

参数转发的回归敏感性也实际验证:在临时运行时刻意丢掉 task_validator,真实 CLI 变成 validation_failed、writeback false、quota false、spend 0;撤销这个测试 mutation 后 exact head 正常 committed、validation passed、spend 1。没有修改 PR 源文件,也没有碰活跃 Goal。Ruff、配置中的 mypy(19 files)、diff whitespace 和 module-budget 都通过。semantic advisory 仅分析两个 changed sources、零 supported carriers;空结果不是语义证明,主要证据是 AST 和真实入口对比。

语义与 CI 对齐

复用现有 EffectiveAction/SettlementStepKind/Turn vocabulary;没有新 shared protocol、默认行为、generic 领域义务或扩大 actor 生命周期的命名。原有身份及独立 validation 是机器强制边界,不是 guidance。没有新的 default-off claim;现有 Operation off/on guards、被绕过的 planning/inspection 路径仍在实际测试中。按照当前 review 配置未读取、轮询或等待远端 CI;批准不自动解除最新 main 集成/merge-readiness 的独立约束。

我的整体评价

APPROVE。长期持续执行和用户体验判断均为 preserved:实际一次结算及零效果重放、完整输入诊断、真实持久恢复和源路由转发都有独立证据。边界更易定位,但不能以行数或测试数代替这些结果。相邻 future-facing pass 已应用为完整 IO owner 抽取,旧体已删除;继续拆更细 callbacks 或强行搭配无关 TS rewrite 会扩大当前维护目标,暂不需要。没有 frontend/Lark companion:九个路径不改变任何 UI、配置、消息或 wire consumer。未宣称全平台/live-host/whole-Goal 验收;批准后检查过期阻塞评审,保留 unresolved 讨论,不合并。

English verdict: APPROVE - 43507c2: The cohesive run-once IO extraction preserves 42 execution statements and the exception handler, five full CLI positive/negative observations, real File settlement and zero-effect replay. Base/head both pass 212 native cases with the same two optional live-host skips. A lost-validator mutation fails the independent public-entry oracle; the unchanged head commits exactly once. Module budget, Ruff and configured mypy pass; no merge or live-provider qualification is claimed.

@huangruiteng
huangruiteng merged commit de57af1 into main Oct 2, 2026
4 of 6 checks passed
@huangruiteng
huangruiteng deleted the codex/fix-turn-run-once-owner branch October 2, 2026 12:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants